package nl.hanze.security;

public class AESD extends Object {
    /* in this setting keysize is always 128 bits and blocksize 128 bits */
    private int[] iExpKey;

    int[] BS= {
        99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118,
        202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192,
        183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21,
        4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117,
        9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132,
        83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207,
        208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168,
        81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210,
        205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115,
        96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219,
        224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121,
        231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8,
        186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138,
        112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158,
        225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223,
        140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22
        };

    int[] IBS= {
        82,9,106,213,48,54,165,56,191,64,163,158,129,243,215,251,
        124,227,57,130,155,47,255,135,52,142,67,68,196,222,233,203,
        84,123,148,50,166,194,35,61,238,76,149,11,66,250,195,78,
        8,46,161,102,40,217,36,178,118,91,162,73,109,139,209,37,
        114,248,246,100,134,104,152,22,212,164,92,204,93,101,182,146,
        108,112,72,80,253,237,185,218,94,21,70,87,167,141,157,132,
        144,216,171,0,140,188,211,10,247,228,88,5,184,179,69,6,
        208,44,30,143,202,63,15,2,193,175,189,3,1,19,138,107,
        58,145,17,65,79,103,220,234,151,242,207,206,240,180,230,115,
        150,172,116,34,231,173,53,133,226,249,55,232,28,117,223,110,
        71,241,26,113,29,41,197,137,111,183,98,14,170,24,190,27,
        252,86,62,75,198,210,121,32,154,219,192,254,120,205,90,244,
        31,221,168,51,136,7,199,49,177,18,16,89,39,128,236,95,
        96,81,127,169,25,181,74,13,45,229,122,159,147,201,156,239,
        160,224,59,77,174,42,245,176,200,235,187,60,131,83,153,97,
        23,43,4,126,186,119,214,38,225,105,20,99,85,33,12,125
        };

    private int mult(int iA, int iB) {
        int iIrrPol=0x11b; int m=8; int i, j, r, t;
        // raw multiplication over Z/(2^32)Z group
        for(i=0, j=1, r=0, t=iA;i<=31;i++,j<<=1,t<<=1) if ((iB&j)!=0) r^=t;
        // reduction mod iIrrPol
        for(i=0, j=0x80000000, t=iIrrPol<<31-m;i<32-m;i++,j>>>=1,t>>>=1) if ((r&j)!=0) r^=t;
        return r;
    }

    private int IMC(int iAlpha) {
        int[] iTemp=new int[4];
        int[] iAlphaC=new int[4];
        int[] iBetaC={0xe, 0x9, 0xd, 0xb};
        int i;
        for(i=0;i<4;i++) iAlphaC[i]=(iAlpha>>(8*i))&0xff;
        for(i=0;i<4;i++) iTemp[i]=mult(iAlphaC[i],iBetaC[(3*i)%4]) | (mult(iAlphaC[i], iBetaC[(3*i+1)%4])<<8) | (mult(iAlphaC[i], iBetaC[(3*i+2)%4])<<16) | (mult(iAlphaC[i], iBetaC[(3*i+3)%4])<<24);
        return iTemp[0] ^ iTemp[1] ^ iTemp[2] ^ iTemp[3];
    }

    public AESD(int[] iKey) {
        int i, temp1, temp2;
        iExpKey = new int[44];
        for(i=0;i<4;i++) iExpKey[i]=iKey[i];
        for(i=4;i<44;i++) {
            temp1=iExpKey[i-1];
            if (i%4==0) {
                temp2=(temp1<<8)|(temp1>>>24);
                temp1=(BS[temp2>>>24]<<24)|(BS[(temp2>>16)&0xff]<<16)|(BS[(temp2>>8)&0xff]<<8)|(BS[temp2&0xff]);
                temp1^=1<<(23+i/4);
            }
            iExpKey[i]=iExpKey[i-4]^temp1;
        }
        for(i=4;i<40;i++) iExpKey[i]=IMC(iExpKey[i]);
    }

    public final int[] ECB(int[] iBlock) {
        int[] iA=new int[4];
        int[] iB=new int[4];
        int i, j;

        // initial key adding
        for(i=0;i<4;i++) iA[i]=iBlock[i]^iExpKey[40+i];

        // 9 standard rounds
        for(i=9;i>0;i--) {
            for(j=0;j<4;j++) iA[j]=IBS[iA[j]&0xff] | (IBS[(iA[j]>>8)&0xff]<<8) | (IBS[(iA[j]>>16)&0xff]<<16) | (IBS[iA[j]>>>24]<<24);
            for(j=0;j<4;j++) iB[j]=(iA[j]&0xff) | (((iA[(j+1)%4]>>8)&0xff)<<8) | (((iA[(j+2)%4]>>16)&0xff)<<16) | ((iA[(j+3)%4]>>>24)<<24);
            for(j=0;j<4;j++) iA[j]=iB[j];
            for(j=0;j<4;j++) iA[j]=IMC(iA[j]);
            for(j=0;j<4;j++) iA[j]^=iExpKey[4*i+j];
        }

        for(j=0;j<4;j++) iA[j]=IBS[iA[j]&0xff] | (IBS[(iA[j]>>8)&0xff]<<8) | (IBS[(iA[j]>>16)&0xff]<<16) | (IBS[iA[j]>>>24]<<24);
        for(j=0;j<4;j++) iB[j]=(iA[j]&0xff) | (((iA[(j+1)%4]>>8)&0xff)<<8) | (((iA[(j+2)%4]>>16)&0xff)<<16) | ((iA[(j+3)%4]>>>24)<<24);
        for(j=0;j<4;j++) iA[j]=iB[j]^iExpKey[j];
        return iA;
    }
}
